home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / elecmail / uupc11ys.zip / MAIL / MAILBLIB.C < prev    next >
C/C++ Source or Header  |  1993-04-10  |  38KB  |  1,072 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    Support routines for UUPC/extended mail user agent              */
  3. /*                                                                    */
  4. /*    History:                                                        */
  5. /*                                                                    */
  6. /*    12 Feb 1991    Created for 1.09d                   ahd          */
  7. /*--------------------------------------------------------------------*/
  8.  
  9. /*--------------------------------------------------------------------*/
  10. /*                           include files                            */
  11. /*--------------------------------------------------------------------*/
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <ctype.h>
  17.  
  18. #include "lib.h"
  19. #include "address.h"
  20. #include "mail.h"
  21. #include "maillib.h"
  22. #include "mailblib.h"
  23. #include "mailsend.h"
  24. #include "hlib.h"
  25. #include "alias.h"
  26. #include "expath.h"
  27.  
  28. /*--------------------------------------------------------------------*/
  29. /*                      Variables global to file                      */
  30. /*--------------------------------------------------------------------*/
  31.  
  32. static int *item_list = NULL;
  33. static size_t next_item;
  34.  
  35. currentfile();
  36.  
  37. /*--------------------------------------------------------------------*/
  38. /*                    Internal function prototypes                    */
  39. /*--------------------------------------------------------------------*/
  40.  
  41. static boolean SearchUser( char *token , char **input, const int bits);
  42.  
  43. static boolean SearchSubject( char *token,
  44.                               char **input,
  45.                               char *trailing,
  46.                               const int bits);
  47.  
  48. /*--------------------------------------------------------------------*/
  49. /*                     Externally known functions                     */
  50. /*--------------------------------------------------------------------*/
  51.  
  52. /*--------------------------------------------------------------------*/
  53. /*    S h o w A l i a s                                               */
  54. /*                                                                    */
  55. /*    Print the expansion of an alias                                 */
  56. /*--------------------------------------------------------------------*/
  57.  
  58. void ShowAlias( const char *alias)
  59. {
  60.    char *fullname = AliasByNick( alias );
  61.    static int level = 0;
  62.    int column = level * 2;
  63.  
  64.    if ( alias == NULL )
  65.    {
  66.       printf("Missing operand\n");
  67.       return;
  68.    }
  69.  
  70. /*--------------------------------------------------------------------*/
  71. /*                        Indent nested calls                         */
  72. /*--------------------------------------------------------------------*/
  73.  
  74.    while(column-- > 0 )
  75.       putchar(' ');
  76.  
  77. /*--------------------------------------------------------------------*/
  78. /*       Show the alias, breaking it down recursively if need be      */
  79. /*--------------------------------------------------------------------*/
  80.  
  81.    if (fullname == NULL)
  82.    {
  83.       char user[MAXADDR];
  84.       char path[MAXADDR];
  85.       char node[MAXADDR];
  86.  
  87.       printf("No alias defined for \"%s\"\n",alias);
  88.  
  89.       column = level * 2 + 2;
  90.       while(column-- > 0 )
  91.          putchar(' ');
  92.  
  93.       user_at_node(alias, path, node, user);
  94.                               /* Reduce address to basics */
  95.       printf("(%s@%s via %s)\n", user, node, path);
  96.    }
  97.    else {
  98.  
  99.       printf("%s is aliased to %s\n", alias, fullname);
  100.  
  101.       if (*fullname == '"')
  102.       {
  103.  
  104.          if ( debuglevel > 1)
  105.          {
  106.             char user[MAXADDR];
  107.             char path[MAXADDR];
  108.             char node[MAXADDR];
  109.  
  110.             ExtractAddress(user,fullname, FALSE);
  111.             user_at_node(user,path,node,user);
  112.                                     /* Reduce address to basics */
  113.             column = level * 2 + 2;
  114.             while(column-- > 0 )
  115.                putchar(' ');
  116.  
  117.             printf("(%s@%s via %s)\n", user, node, path);
  118.          }
  119.       }
  120.       else {
  121.          char buf[LSIZE];
  122.  
  123.          strcpy( buf, fullname );
  124.          fullname = strtok( buf , WHITESPACE "," );
  125.  
  126.          while (fullname != NULL )
  127.          {
  128.             char *save = strtok( NULL , "");
  129.             level++;             /* Bump up a level for recursive calls */
  130.             ShowAlias(fullname);
  131.             level--;             /* Restore indent level                */
  132.             fullname = strtok( save , " ," );
  133.          } /* while */
  134.       } /* else */
  135.    } /* else */
  136.  
  137. } /* ShowAlias */
  138.  
  139. /*--------------------------------------------------------------------*/
  140. /*    S a v e I t e m                                                 */
  141. /*                                                                    */
  142. /*    Save an item in another mailbox                                 */
  143. /*--------------------------------------------------------------------*/
  144.  
  145. boolean SaveItem( const int item,
  146.                const boolean delete,
  147.                const copyopt headers,
  148.                char *fname,
  149.                const ACTION verb)
  150. {
  151.    char filename[FILENAME_MAX];
  152.    char *s = "?";
  153.    FILE *stream;
  154.  
  155.    if (fname == NULL)
  156.       fname = "~/mbox";
  157.  
  158. /*--------------------------------------------------------------------*/
  159. /*                        Build the file name                         */
  160. /*--------------------------------------------------------------------*/
  161.  
  162.    switch (*fname)
  163.    {
  164.       case '=':         /* relative to home directory? */
  165.             printf("Syntax is obsolete ... use \"~/%s\"", fname + 1 );
  166.             mkfilename(filename, E_homedir, ++fname);
  167.             break;
  168.  
  169.       case '+':         /* Relative to mail directory?   */
  170.             mkmailbox(filename, ++fname);
  171.             break;
  172.  
  173.       default:
  174.       case '~':         /* Relative to home directory?            */
  175.             strcpy( filename , fname );
  176.             if (expand_path( filename , NULL, E_homedir, E_mailext ) == NULL)
  177.                return FALSE;
  178.             break;
  179.    }  /* end switch */
  180.  
  181. /*--------------------------------------------------------------------*/
  182. /*               Announce our action based on the verb                */
  183. /*--------------------------------------------------------------------*/
  184.  
  185.    switch( verb )
  186.    {
  187.       case M_COPY:
  188.          s = "Copying";
  189.          break;
  190.  
  191.       case M_SAVE:
  192.          s = "Saving";
  193.          break;
  194.  
  195.       case M_WRITE:
  196.          s = "Writing";
  197.          break;
  198.    } /* switch */
  199.  
  200.    printf("%s item %d to %s\n", s , item + 1, filename );
  201.  
  202. /*--------------------------------------------------------------------*/
  203. /*                     Open the mailox to save to                     */
  204. /*--------------------------------------------------------------------*/
  205.  
  206.    if ((stream = FOPEN(filename, "a",TEXT_MODE)) == nil(FILE))
  207.    {
  208.       printf("Cannot append to %s\n", filename);
  209.       return FALSE;
  210.    } /* if */
  211.  
  212.    CopyMsg(item, stream, headers, FALSE);
  213.    fclose(stream);
  214.  
  215. /*--------------------------------------------------------------------*/
  216. /*                   Delete the message if required                   */
  217. /*--------------------------------------------------------------------*/
  218.  
  219.    if (letters[item].status < M_DELETED)
  220.       letters[item].status = delete ? M_DELETED : M_SAVED;
  221.  
  222.    return TRUE;
  223. } /* SaveItem */
  224.  
  225.  
  226. /*--------------------------------------------------------------------*/
  227. /*    P o s i t i o n                                                 */
  228. /*                                                                    */
  229. /*    Makes reasonable choice of next letter to examine               */
  230. /*--------------------------------------------------------------------*/
  231.  
  232. int Position(int absolute, int relative, int start)
  233. {
  234.    int current = start;
  235.  
  236. /*--------------------------------------------------------------------*/
  237. /*                   Explicitly position the letter                   */
  238. /*--------------------------------------------------------------------*/
  239.  
  240.    if ( absolute )
  241.    {
  242.       current = absolute ;
  243.       if (( current <= letternum ) && (current > 0))
  244.          return current - 1;
  245.       else if ( current >= letternum )
  246.          printf("Item %d does not exist, last item in mailbox is %d\n",
  247.                current , letternum);
  248.       else
  249.          printf("Cannot backup beyond top of mailbox\n");
  250.  
  251.       return start;
  252.    } /* if */
  253.  
  254. /*--------------------------------------------------------------------*/
  255. /*           Position the pionter relative to current item            */
  256. /*--------------------------------------------------------------------*/
  257.  
  258.    if ( relative )
  259.    {
  260.       int move ;
  261.       move = (relative > 0) ? 1 : -1;
  262.       if ( (current + move) == letternum )
  263.       {
  264.          printf("At end of mailbox\n");
  265.          return current;
  266.       }
  267.  
  268.       while ( relative )
  269.       {
  270.          current += move;
  271.          if ( current >= letternum )
  272.          {
  273.             printf("Item %d does not exist, last item in mailbox is %d\n",
  274.                   current+relative, letternum);
  275.             return start;
  276.          }
  277.          else if ( current < 0 )
  278.          {
  279.             printf("Cannot backup beyond top of mailbox\n");
  280.             return start;
  281.          }
  282.          else if (letters[current].status != M_DELETED)
  283.             relative -= move;
  284.       } /* while */
  285.  
  286.       return current;
  287.    } /* if */
  288.  
  289. /*--------------------------------------------------------------------*/
  290. /*                   Implicitly position the letter                   */
  291. /*--------------------------------------------------------------------*/
  292.  
  293.    while (current < letternum)
  294.    {
  295.       if (letters[current].status != M_DELETED)
  296.          return current;
  297.       else
  298.          ++current;
  299.    } /* while */
  300.  
  301.    current = start;
  302.  
  303.    while (current-- > 0)
  304.       if (letters[current].status != M_DELETED)
  305.          return current;
  306.  
  307.    printf("At end of mailbox\n");
  308.    return start;
  309. } /* Position */
  310.  
  311. /*--------------------------------------------------------------------*/
  312. /*    D e l i v e r M a i l                                           */
  313. /*                                                                    */
  314. /*    Compose interactive outgoing mail                               */
  315. /*--------------------------------------------------------------------*/
  316.  
  317. boolean DeliverMail( char *addresses , int item)
  318. {
  319.    char *Largv[MAXADDRS];
  320.    int   Largc;
  321.  
  322.    Largc = getargs(addresses , Largv );
  323.    return Collect_Mail(stdin, Largc , Largv, item , FALSE);
  324. } /* DeliverMail */
  325.  
  326. /*--------------------------------------------------------------------*/
  327. /*    R e p l y                                                       */
  328. /*                                                                    */
  329. /*    Reply to incoming mail                                          */
  330. /*--------------------------------------------------------------------*/
  331.  
  332. boolean Reply( const int current )
  333. {
  334.    char *Largv[MAXADDRS];
  335.    char subject[LSIZE];
  336.    char addr[LSIZE];
  337.    char line[LSIZE];
  338.    char *column;
  339.    int   Largc = 0;
  340.  
  341.    subject[0] = '\0';
  342.  
  343. /*--------------------------------------------------------------------*/
  344. /*               Determine if we can reply to the mail                */
  345. /*--------------------------------------------------------------------*/
  346.  
  347.    if (!RetrieveLine(letters[current].replyto, addr, LSIZE))
  348.    {
  349.       printf("Cannot determine return address\n");
  350.       return FALSE;
  351.    }
  352.  
  353. /*--------------------------------------------------------------------*/
  354. /*                  Get the incoming subject, if any                  */
  355. /*--------------------------------------------------------------------*/
  356.  
  357.    if (RetrieveLine(letters[current].subject, line, LSIZE))
  358.    {
  359.       register char  *sp = line;
  360.  
  361.       while (!isspace(*sp))     /* Skip "Subject:"      */
  362.          sp++;
  363.       while (isspace(*sp))      /* Skip leading whitespace */
  364.          sp++;
  365.       Largv[Largc++] = "-s";
  366.  
  367.       if (!equalni(sp,"Re:",3))
  368.          strcat(subject,"Re: ");
  369.       strcat(subject,sp);
  370.       Largv[Largc++] = subject;
  371.    }
  372.  
  373. /*--------------------------------------------------------------------*/
  374. /*                   Get the extract return address                   */
  375. /*--------------------------------------------------------------------*/
  376.  
  377.    column = addr;
  378.    while (!isspace(*column) && strlen(column))
  379.       column++;
  380.  
  381.    BuildAddress(line,column);      /* Build standard "To:" addr  */
  382.    printf("Replying to %s\n", line);
  383.  
  384. /*--------------------------------------------------------------------*/
  385. /*                    Format the outgoing address                     */
  386. /*--------------------------------------------------------------------*/
  387.  
  388.    Largv[Largc++] = line;
  389.  
  390.    if (letters[current].status < M_ANSWERED)
  391.       letters[current].status = M_ANSWERED;
  392.  
  393.    return Collect_Mail(stdin, Largc, Largv, current, TRUE);
  394.  
  395. } /* Reply */
  396.  
  397.  
  398. /*--------------------------------------------------------------------*/
  399. /*    F o r w a r d I t e m                                           */
  400. /*                                                                    */
  401. /*    Forward (resend) mail to another address                        */
  402. /*--------------------------------------------------------------------*/
  403.  
  404. boolean ForwardItem( const int item , const char *string )
  405. {
  406.    FILE *stream;
  407.    char  *Largv[MAXADDRS];
  408.    char buf[LSIZE];
  409.    char tmailbag[FILENAME_MAX];
  410.    int   Largc;
  411.    boolean success;
  412.  
  413. /*--------------------------------------------------------------------*/
  414. /*              copy current message to a temporary file              */
  415. /*--------------------------------------------------------------------*/
  416.  
  417.    mktempname(tmailbag, "TMP");
  418.    stream = FOPEN(tmailbag, "w",TEXT_MODE);
  419.    if (stream == NULL )
  420.    {
  421.       printerr(tmailbag);
  422.       return FALSE;
  423.    } /* if */
  424.  
  425.    CopyMsg(item, stream, noreceived,FALSE);
  426.  
  427.    fclose(stream);
  428.  
  429. /*--------------------------------------------------------------------*/
  430. /*               mail the content of the temporary file               */
  431. /*--------------------------------------------------------------------*/
  432.  
  433.    stream = FOPEN(tmailbag, "r",TEXT_MODE);
  434.    if (stream == NULL )
  435.    {
  436.       printerr(tmailbag);
  437.       panic();
  438.    }
  439.  
  440.    strcpy( buf , string );
  441.    Largc = getargs( buf , Largv );
  442.    success = Send_Mail(stream, Largc , Largv, NULL, TRUE);
  443.  
  444. /*--------------------------------------------------------------------*/
  445. /*                   Clean up and return to caller                    */
  446. /*--------------------------------------------------------------------*/
  447.  
  448.    if (letters[item].status < (int) M_FORWARDED)
  449.       letters[item].status = (int) M_FORWARDED;
  450.    remove(tmailbag);
  451.  
  452.    return success;
  453. } /* ForwardItem */
  454.  
  455.  
  456. /*--------------------------------------------------------------------*/
  457. /*    s u b s h e l l                                                 */
  458. /*                                                                    */
  459. /*    Invoke inferior command processor                               */
  460. /*--------------------------------------------------------------------*/
  461.  
  462. void subshell( char *command )
  463. {
  464.    if ( command == NULL )
  465.    {
  466.       static char *new_prompt = NULL;
  467.  
  468.       char *exit_prompt =  "PROMPT=Enter EXIT to return to MAIL$_";
  469.       char *old_prompt;
  470.  
  471.       if ( new_prompt == NULL )
  472.       {
  473.          old_prompt = getenv( "PROMPT" );
  474.          if ( old_prompt == NULL )
  475.             old_prompt = "$p$g";
  476.  
  477.          new_prompt = malloc( strlen( old_prompt ) + strlen( exit_prompt ) + 1);
  478.          checkref( new_prompt );
  479.  
  480.          strcpy( new_prompt , exit_prompt );
  481.          strcat( new_prompt, old_prompt );
  482.  
  483.          if (putenv( new_prompt ) )
  484.          {
  485.             printmsg(0,"Prompt update failed ...");
  486.             printerr("putenv");
  487.          } /* if (putenv( new_prompt ) ) */
  488.  
  489.       } /* if ( new_prompt == NULL ) */
  490.  
  491.       system( getenv( "COMSPEC" ) );
  492.    } /* if */
  493.    else
  494.       system ( command );
  495. } /* subshell */
  496.  
  497. /*--------------------------------------------------------------------*/
  498. /*    S e l e c t I t e m s                                           */
  499. /*                                                                    */
  500. /*    Select mail items to be processed by the current command        */
  501. /*--------------------------------------------------------------------*/
  502.  
  503. boolean SelectItems( char **input, int current , int bits)
  504. {
  505.    char *next_token = *input;
  506.    char *token = NULL;
  507.    char trailing[LSIZE];      /* for saving trailing part of line    */
  508.    int item;
  509.    boolean hit = FALSE;
  510.  
  511. /*--------------------------------------------------------------------*/
  512. /*                 Reset all mail items to unselected                 */
  513. /*--------------------------------------------------------------------*/
  514.  
  515.    next_item = 0;
  516.  
  517. /*--------------------------------------------------------------------*/
  518. /*            If no operands, return the current mail item            */
  519. /*--------------------------------------------------------------------*/
  520.  
  521.    if ( *input == NULL )
  522.    {
  523.       SetItem( current+1 );
  524.       return SetTrailing( input , bits );
  525.    }
  526.  
  527. /*--------------------------------------------------------------------*/
  528. /*             Select all items if the user requested so              */
  529. /*--------------------------------------------------------------------*/
  530.  
  531.    strcpy( trailing , next_token );
  532.    token = strtok( next_token , WHITESPACE );
  533.    if (equal(token,"*"))      /* Select all items?                   */
  534.    {
  535.       *input = strtok( NULL , "" );
  536.  
  537.       for ( item = 1; item <= letternum; item++)
  538.          SetItem( item );
  539.  
  540.       return SetTrailing( input , bits );
  541.    } /* if */
  542.  
  543. /*--------------------------------------------------------------------*/
  544. /*   If the first token begins with a slash (/), scan for items       */
  545. /*   with the subject.                                                */
  546. /*--------------------------------------------------------------------*/
  547.  
  548.    if ( *token == '/' )
  549.       return SearchSubject( token, input, trailing, bits);
  550.  
  551. /*--------------------------------------------------------------------*/
  552. /*          Scan the line until we hit a non-numeric operand          */
  553. /*--------------------------------------------------------------------*/
  554.  
  555.    while ( token != NULL)
  556.    {
  557.       boolean success = TRUE;
  558.       next_token = strtok( NULL , "");
  559.                               /* Remember next of line for next pass */
  560.  
  561.       if (Numeric( token ))
  562.          hit = success = SetItem( atoi(token) );
  563.       else if (equal( token, "$"))
  564.          hit = success = SetItem( letternum );
  565.       else if (equal( token, "."))
  566.          hit = success = SetItem( current + 1 );
  567.       else if (strpbrk(token,"@!") != NULL ) /* User id?             */
  568.          break;                  /* Yes --> Exit loop gracefully     */
  569.       else if (isdigit(*token) || (*token == '$') || (*token == '.'))
  570.                                  /* Is it start-end combination?     */
  571.       {                          /* Yes --> Handle it                */
  572.          char *start, *end ;
  573.          int  istart, iend;
  574.          start = strtok( token , "-");
  575.          end   = strtok( NULL , "");
  576.  
  577.          if (equal(start,"$"))
  578.             istart = letternum;
  579.          else if (equal(start,"."))
  580.             istart = current + 1 ;
  581.          else if (!Numeric( start ))
  582.          {
  583.             printf("%s: Operand is not numeric\n", start );
  584.             return FALSE;
  585.          } /* if */
  586.          else
  587.             istart = atoi( start );
  588.  
  589.          if ( (end == NULL) )
  590.          {
  591.             printf("Missing end of item range\n" );
  592.             return FALSE;
  593.          } /* if */
  594.  
  595.          if (equal(end,"$"))
  596.             iend = letternum;
  597.          else if (equal(end,"."))
  598.             iend = current + 1 ;
  599.          else if (!Numeric( end ))
  600.          {
  601.             printf("%s: Operand is not numeric\n", end );
  602.             return FALSE;
  603.          } /* if */
  604.          else
  605.             iend = atoi( end );
  606.  
  607.          if ( iend < istart)
  608.          {
  609.             printf("Ending item (%d) is less than starting item (%d)\n",
  610.                    iend , istart );
  611.             return FALSE;
  612.          } /* if */
  613.  
  614.          for ( item = istart; (item <= iend) && success; item++ )
  615.             hit = success = SetItem ( item );
  616.  
  617.       } /* else */
  618.       else
  619.          break ;
  620.  
  621.       if ( !success )
  622.          return FALSE;
  623.  
  624.       if ( next_token != NULL )
  625.       {
  626.          strcpy( trailing , next_token );
  627.                               /* Save current line so we can back up */
  628.          token = strtok( next_token, WHITESPACE );
  629.       }
  630.       else
  631.          token = NULL;
  632.    } /* while */
  633.  
  634. /*--------------------------------------------------------------------*/
  635. /*   Determine if we have a user id to search for.  This is harder    */
  636. /*   than the above search for subject lines, because the user id     */
  637. /*   doesn't have to have a special delimiter; thus, we do our        */
  638. /*   best to discard other types of items and assume a user id        */
  639. /*   only if we don't know what it is.                                */
  640. /*--------------------------------------------------------------------*/
  641.  
  642.    if ( ! hit )
  643.    {
  644.       if ( (bits & (FILE_OP | USER_OP)) == 0x0000)
  645.       {
  646.          *input = next_token;
  647.          return SearchUser( token, input, bits);
  648.       }
  649.       else if ((bits & USER_OP) == 0x0000)
  650.       {
  651.          if ((strpbrk(token,"@%!") != NULL) || (next_token != NULL))
  652.          {
  653.             *input = next_token;
  654.             return SearchUser( token, input, bits);
  655.          }
  656.       }
  657.    } /* if (! hit) */
  658.  
  659. /*--------------------------------------------------------------------*/
  660. /*      Handle trailing operands when user selected items by number   */
  661. /*--------------------------------------------------------------------*/
  662.  
  663.    if ( token != NULL )
  664.    {
  665.       if (!hit)               /* Any numeric operands?               */
  666.          SetItem( current+1 );   /* No --> Set current as default    */
  667.       strcpy( *input, trailing );
  668.    }
  669.    else
  670.       *input = NULL ;
  671.  
  672.    return SetTrailing( input , bits );
  673.  
  674. } /* SelectItems */
  675.  
  676.  
  677. /*--------------------------------------------------------------------*/
  678. /*    S e a r c h S u j e c t                                         */
  679. /*                                                                    */
  680. /*    Search for mail items to select by the subject                  */
  681. /*--------------------------------------------------------------------*/
  682.  
  683. static boolean SearchSubject( char *token,
  684.                               char **input,
  685.                               char *trailing,
  686.                               const int bits)
  687. {
  688.    char line[LSIZE];
  689.    int item;
  690.    char *next_token;
  691.    boolean hit = FALSE;
  692.  
  693.    token = strtok(trailing,"/");    /* Get subject to search      */
  694.    if ( token == NULL )
  695.    {
  696.       printf("Missing subject to search for\n");
  697.       return FALSE;
  698.    }
  699.    token = strlwr(token);  /* Case insensitive search             */
  700.    next_token = strtok(NULL,"");
  701.                            /* Get rest of line                    */
  702.    for ( item = 1; item <= letternum; item++)
  703.    {
  704.       if (letters[item-1].status == M_DELETED)
  705.          continue;
  706.       if (
  707.            RetrieveLine(letters[item-1].subject, line, LSIZE ) &&
  708.           strstr( strlwr(line), token ))
  709.                            /* This item have subject?             */
  710.       {
  711.          SetItem( item );
  712.          hit = TRUE;
  713.       } /* if */
  714.    } /* for */
  715.  
  716.    if (hit)                /* Did we find the string for user?    */
  717.    {
  718.       if ( next_token == NULL )
  719.          *input = NULL;
  720.       else
  721.          strcpy( *input, next_token );
  722.       return SetTrailing( input , bits ); /* Yes --> Success      */
  723.    } /* if (hit) */
  724.    else {
  725.       printf("No mail items found with subject \"%s\"\n",token);
  726.       return FALSE;
  727.    }  /* else */
  728. } /* SearchSubject */
  729.  
  730.  
  731. /*--------------------------------------------------------------------*/
  732. /*    S e a r c h U s e r                                             */
  733. /*                                                                    */
  734. /*    Search for a user id on mail items                              */
  735. /*--------------------------------------------------------------------*/
  736.  
  737. static boolean SearchUser( char *token , char **input, const int bits)
  738. {
  739.    char line[LSIZE];
  740.    int item;
  741.    boolean hit = FALSE;
  742.  
  743.    token = strlwr(token);  /* Case insensitive search          */
  744.  
  745. /*--------------------------------------------------------------------*/
  746. /*    Our loop is as follows for each item in the mailbox:            */
  747. /*                                                                    */
  748. /*       If the letter is deleted, ignore it                          */
  749. /*       If the From line can be retrieved from the item:             */
  750. /*                                                                    */
  751. /*          1) Read the line                                          */
  752. /*          2) Scan up to the first whitespace                        */
  753. /*             2a) If there is no whitespace, use entire line         */
  754. /*             2b) If there is whitespace, step past it to next       */
  755. /*                 non-whitespace character                           */
  756. /*          3) Lowercase the line                                     */
  757. /*          4) Scan for the the target address in the line:           */
  758. /*             4a) If found select the item for processing            */
  759. /*             4b) If not found, build a standard outgoing address    */
  760. /*                 and search again.  If found, select the item       */
  761. /*                                                                    */
  762. /*       If the From line cannot be retrieved:                        */
  763. /*          1) call ReturnAddress to format the return address        */
  764. /*             (Because the line cannot be retrieved, it will         */
  765. /*              "-- unknown --", the same string displayed by         */
  766. /*              Headers.                                              */
  767. /*          2) Scan for the the target address in the returned        */
  768. /*             address                                                */
  769. /*          3) If found, select the item for processing               */
  770. /*--------------------------------------------------------------------*/
  771.  
  772.    for ( item = 1; item <= letternum; item++)
  773.    {
  774.       printmsg(2,"Examining item %d", item);
  775.       if (letters[item-1].status == M_DELETED)
  776.          continue;
  777.       if (RetrieveLine(letters[item - 1].from, line, LSIZE))
  778.       {
  779.          char *addr  = strpbrk(line,WHITESPACE);
  780.          if (addr == NULL)    /* Whitespace in input line?        */
  781.             addr = line;      /* No --> Use entire line           */
  782.          else
  783.             while(isspace(*addr))   /* Yes --> Skip past first WS */
  784.                addr++;
  785.          printmsg(2,"SearchUser: Address %d is: %s",item-1,addr);
  786.          if ( strstr( strlwr(addr), token ))    /* Find address?  */
  787.             hit = SetItem( item );  /* Yes--> Select item for use */
  788.          else {                     /* No--> Expand & search again*/
  789.             char result[MAXADDR];
  790.             BuildAddress( result, addr);
  791.                            /* Get expanded address for user       */
  792.             printmsg(2,"SearchUser: Formatted address %d is: %s",
  793.                   item-1,result);
  794.             if ( strstr( strlwr(result), token ))
  795.                            /* This item have correct sender?      */
  796.                hit = SetItem( item );  /* Yes --> Set it          */
  797.             else
  798.                printmsg(2,"SearchUser: Item %d not selected.",
  799.                      item-1);
  800.          } /* else */
  801.       } /* if */
  802.       else {
  803.          ReturnAddress(line,&letters[item - 1]);
  804.                            /* Get standard error text for letter  */
  805.          printmsg(2,"SearchUser: Default address %d is: %s",
  806.                   item-1,line);
  807.          if ( strstr( strlwr(line), token ))
  808.                            /* This item have correct sender?      */
  809.             hit = SetItem( item );  /* Yes --> Set it             */
  810.       } /* else */
  811.    } /* for */
  812.  
  813. /*--------------------------------------------------------------------*/
  814. /*        End of loop; determined success and return to caller        */
  815. /*--------------------------------------------------------------------*/
  816.  
  817.    if (hit)             /* Did we find the string for user?    */
  818.       return SetTrailing( input , bits ); /* Yes --> Success   */
  819.    else {
  820.       printf("No mail items found from \"%s\"\n",token);
  821.       return FALSE;
  822.    }  /* else */
  823.  
  824. }  /* SearchUser */
  825.  
  826.  
  827. /*--------------------------------------------------------------------*/
  828. /*    S e t T r a i l i n g                                           */
  829. /*                                                                    */
  830. /*    Determine success of command parse based on trailing operands   */
  831. /*--------------------------------------------------------------------*/
  832.  
  833. boolean SetTrailing( char **input, int bits )
  834. {
  835.  
  836. /*--------------------------------------------------------------------*/
  837. /*                        Trim trailing spaces                        */
  838. /*--------------------------------------------------------------------*/
  839.  
  840.    if (*input != NULL)
  841.    {
  842.       char *s = *input;
  843.       while( isspace(*s))
  844.          s++;
  845.       if ( *s == '\0' )       /* Anything left in string?            */
  846.          *input = NULL;       /* No --> Flag input as NULL           */
  847.       else
  848.          *input = s;          /* Yes --> Point input to next operand */
  849.    }
  850.  
  851. /*--------------------------------------------------------------------*/
  852. /*                     Trailing address operands?                     */
  853. /*--------------------------------------------------------------------*/
  854.  
  855.    if (( bits & USER_OP ) || ( *input == NULL ))
  856.       return TRUE;            /* Let Get_Operand check operands      */
  857.  
  858. /*--------------------------------------------------------------------*/
  859. /*                        Trailing file name?                         */
  860. /*--------------------------------------------------------------------*/
  861.  
  862.    if ( bits & FILE_OP )
  863.    {
  864.       char *token = strtok( *input , WHITESPACE );
  865.       token = strtok( NULL , "" );
  866.  
  867.       if ( token == NULL )
  868.          return TRUE;
  869.       else {
  870.          printf("%s: Only one file operand allowed on command\n",
  871.             token);
  872.          return FALSE;
  873.       } /* else */
  874.    } /* if */
  875.  
  876. /*--------------------------------------------------------------------*/
  877. /*                   No operand allowed; reject it                    */
  878. /*--------------------------------------------------------------------*/
  879.  
  880.    printf("%s: Unknown operand on command\n", *input);
  881.    return FALSE;
  882.  
  883. } /* SetTrailing */
  884.  
  885. /*--------------------------------------------------------------------*/
  886. /*    S e t I t e m                                                   */
  887. /*                                                                    */
  888. /*    Validate and select a single item                               */
  889. /*--------------------------------------------------------------------*/
  890.  
  891. boolean SetItem( int item )
  892. {
  893.    if ( item_list == NULL )
  894.    {
  895.       item_list = calloc( letternum, sizeof *item_list);
  896.       checkref( item_list );
  897.    }
  898.  
  899.    if ((item > 0) && ( item <= letternum ))
  900.    {
  901.       item_list[ next_item++ ] = item - 1;
  902.       return TRUE;
  903.    }
  904.    else {
  905.       printf("Invalid item (%d) selected for processing\n",item);
  906.       return FALSE;
  907.    } /* else */
  908. } /* SetItem */
  909.  
  910. /*--------------------------------------------------------------------*/
  911. /*    G e t _ O p e r a n d                                           */
  912. /*                                                                    */
  913. /*    Get next operand to process                                     */
  914. /*--------------------------------------------------------------------*/
  915.  
  916. boolean Get_Operand( int *item,
  917.                      char **token,
  918.                      int bits,
  919.                      boolean first_pass )
  920. {
  921.  
  922. /*--------------------------------------------------------------------*/
  923. /*                         Handle no operand                          */
  924. /*--------------------------------------------------------------------*/
  925.  
  926.    if (bits & NO_OPERANDS)
  927.    {
  928.       if ( *token == NULL )
  929.          return first_pass;
  930.       else {
  931.          printf("Operands not allowed on this command!\n");
  932.          return FALSE;
  933.       } /* else */
  934.    }
  935.  
  936. /*--------------------------------------------------------------------*/
  937. /*        User operands are like string operands, but required        */
  938. /*--------------------------------------------------------------------*/
  939.  
  940.    if ( (bits & USER_OP) && (*token == NULL))
  941.    {
  942.       printf("Missing addressees for command\n");
  943.       return FALSE;
  944.    }
  945. /*--------------------------------------------------------------------*/
  946. /*                       Handle letter operand                        */
  947. /*--------------------------------------------------------------------*/
  948.  
  949.    if ( bits & LETTER_OP )
  950.    {
  951.       static size_t subscript;
  952.       subscript = first_pass ? 0 : subscript + 1;
  953.  
  954.       if (subscript < next_item)
  955.       {
  956.          *item = item_list[subscript];
  957.          return TRUE;
  958.       } /* else */
  959.       else {
  960.          free( item_list );
  961.          item_list = NULL;
  962.          return FALSE;
  963.       } /* else */
  964.    } /* if*/
  965.  
  966. /*--------------------------------------------------------------------*/
  967. /*                   Handle string operands                           */
  968. /*--------------------------------------------------------------------*/
  969.  
  970.    if ( bits & (STRING_OP | USER_OP))
  971.    {
  972.       char *buf = *token;
  973.       if (first_pass &&
  974.           (buf != NULL) &&
  975.           ( buf[ strlen(buf) - 1 ] == '\n'))
  976.          buf[ strlen(buf) - 1 ] = '\0';
  977.       return first_pass;
  978.    }
  979.  
  980. /*--------------------------------------------------------------------*/
  981. /*                     Handle tokenized operands                      */
  982. /*--------------------------------------------------------------------*/
  983.  
  984.    if ( bits & TOKEN_OP )
  985.    {
  986.       static char *rest = NULL ;
  987.       if (first_pass)
  988.          rest = *token;
  989.  
  990.       if ( *rest == (char ) NULL)
  991.       {
  992.          *token = NULL;
  993.          return first_pass;
  994.       } /* if */
  995.  
  996.       *token = strtok( rest , WHITESPACE );
  997.       if ( *token == (char) NULL)
  998.       {
  999.          rest = NULL;
  1000.          return first_pass;
  1001.       }
  1002.       else {
  1003.          rest = strtok( NULL , "" );
  1004.          return TRUE;
  1005.       } /* else */
  1006.    } /* if */
  1007.  
  1008. /*--------------------------------------------------------------------*/
  1009. /*                      Handle integer operands                       */
  1010. /*--------------------------------------------------------------------*/
  1011.  
  1012.    if ( bits & INTEGER_OP)
  1013.    {
  1014.       char *p;
  1015.       if ( (*token == NULL) || ! first_pass )
  1016.       {
  1017.          *item = 1;
  1018.          return first_pass;
  1019.       }
  1020.       p = strtok( *token, WHITESPACE );
  1021.  
  1022.       if (!Numeric( p ))
  1023.       {
  1024.          printf("%s: Operand is not numeric\n", p );
  1025.          return FALSE;
  1026.       } /* if */
  1027.  
  1028.       *item = atoi( p );
  1029.       p = strtok( NULL, WHITESPACE );
  1030.       if (p != NULL )
  1031.       {
  1032.          printf("%s: extra operand not allowed on command\n", p);
  1033.          return FALSE;
  1034.       }
  1035.       return TRUE;
  1036.    } /* if */
  1037.  
  1038. /*--------------------------------------------------------------------*/
  1039. /*                   We cannot handle this command                    */
  1040. /*--------------------------------------------------------------------*/
  1041.  
  1042.    printf("Unknown processing option = %x, cannot process command\n",
  1043.          bits);
  1044.    return FALSE;
  1045.  
  1046. } /* Get_Operand */
  1047.  
  1048. /*--------------------------------------------------------------------*/
  1049. /*    P u s h I t e m L i s t                                         */
  1050. /*                                                                    */
  1051. /*    Save item parsing list                                          */
  1052. /*--------------------------------------------------------------------*/
  1053.  
  1054. int PushItemList( int **save_list )
  1055. {
  1056.    *save_list = item_list;
  1057.    item_list = NULL;
  1058.    return next_item;
  1059. } /* PushItemList */
  1060.  
  1061. /*--------------------------------------------------------------------*/
  1062. /*    P o p I t e m L i s t                                           */
  1063. /*                                                                    */
  1064. /*    Restore parsing information saved by PushItemList               */
  1065. /*--------------------------------------------------------------------*/
  1066.  
  1067. void PopItemList( int *save_list, int save_item )
  1068. {
  1069.    item_list = save_list;
  1070.    next_item = save_item;
  1071. } /* PopItemList */
  1072.